package com.ruoyi.jt808.service.handler;

import com.ruoyi.jt808.common.TPMSConsts;
import com.ruoyi.jt808.server.SessionManager;
import com.ruoyi.jt808.service.codec.MsgDecoder;
import com.ruoyi.jt808.util.JT808ProtocolUtils;
import com.ruoyi.jt808.util.PacketSplitDetector;
import com.ruoyi.jt808.vo.PackageData;
import com.ruoyi.jt808.vo.Session;
import io.netty.buffer.ByteBuf;
import io.netty.channel.ChannelHandler;
import io.netty.channel.ChannelHandlerContext;
import io.netty.channel.ChannelInboundHandlerAdapter;
import io.netty.handler.timeout.IdleState;
import io.netty.handler.timeout.IdleStateEvent;
import io.netty.util.ReferenceCountUtil;

import cn.hutool.core.util.ArrayUtil;
import cn.hutool.core.util.HexUtil;

import lombok.extern.slf4j.Slf4j;
import net.bytebuddy.implementation.bytecode.Throw;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.stereotype.Component;

@Slf4j
@Component
@ChannelHandler.Sharable
public class TCPServerHandler extends ChannelInboundHandlerAdapter {

	private final Logger logger = LoggerFactory.getLogger(getClass());

	private final SessionManager sessionManager;
	private final MsgDecoder decoder;
	private final MessageHandler messageHandler;
	private JT808ProtocolUtils protocolUtils = new JT808ProtocolUtils();

	public TCPServerHandler() {
		this.sessionManager = SessionManager.getInstance();
		this.decoder = new MsgDecoder();
		this.messageHandler = new MessageHandler();
	}

	@Override
	public void channelRead(ChannelHandlerContext ctx, Object msg){
		try {

			ByteBuf buf = (ByteBuf)msg;
			if (buf.readableBytes() <= 0) {
				return;
			}
			byte[] bs = new byte[buf.readableBytes()];
			buf.readBytes(bs);

			/*boolean b = PacketSplitDetector.isCompletePacket(buf);
			if (!b){
				log.info("包体长度不够");
				return;
			}*/

			// 格式化消息为16进制字符串
			byte[] flagBytes = new byte[] {TPMSConsts.pkg_delimiter};
			String dataMsg =
					HexUtil.format(HexUtil.encodeHexStr(ArrayUtil.addAll(flagBytes, bs, flagBytes))).toUpperCase();
			if (log.isInfoEnabled()) {
				log.info("[client -> server],data: {}", dataMsg);
			}
			// 数据转义
			byte[] covertByte = protocolUtils.covertByte(bs);

			PackageData pkg = this.decoder.bytes2PackageData(covertByte);
			// 引用channel,以便回送数据给硬件
			pkg.setChannel(ctx.channel());

			messageHandler.processPackageData(pkg);
		} catch (Exception e) {
			logger.error("",e);
		} finally {
			release(msg);
		}
	}

	@Override
	public void exceptionCaught(ChannelHandlerContext ctx, Throwable cause) { // (4)
		logger.error("发生异常:{}", cause.getMessage());
		cause.printStackTrace();
	}

	@Override
	public void channelActive(ChannelHandlerContext ctx) throws Exception {
		Session session = Session.buildSession(ctx.channel());
		sessionManager.put(session.getId(), session);
		logger.debug("终端连接:{}", session);
	}

	@Override
	public void channelInactive(ChannelHandlerContext ctx) throws Exception {
		final String sessionId = ctx.channel().id().asLongText();
		Session session = sessionManager.findBySessionId(sessionId);
		this.sessionManager.removeBySessionId(sessionId);
		logger.debug("终端断开连接:{}", session);
		ctx.channel().close();
		// ctx.close();
	}

	@Override
	public void userEventTriggered(ChannelHandlerContext ctx, Object evt) throws Exception {
		if (IdleStateEvent.class.isAssignableFrom(evt.getClass())) {
			IdleStateEvent event = (IdleStateEvent) evt;
			if (event.state() == IdleState.READER_IDLE) {
				Session session = this.sessionManager.removeBySessionId(Session.buildId(ctx.channel()));
				logger.error("服务器主动断开连接:{}", session);
				ctx.close();
			}
		}
	}

	private void release(Object msg) {
		try {
			ReferenceCountUtil.release(msg);
		} catch (Exception e) {
			e.printStackTrace();
		}
	}
}